package service

import (
	"errors"
	"strconv"
	"strings"
	"vtrip/internal/model"
	"vtrip/pkg/app"
)

// GetAllItineraryRequest 查询用户所有行程
type GetAllItineraryRequest struct {
	Page     int `form:"page,default=0"`
	PageSize int `form:"page_size,default=0"`
}

// PublishItineraryRequest 创建新的行程
type PublishItineraryRequest struct {
	Title          string `form:"title" binding:"required"`
	Slogan         string `form:"slogan" binding:"required"`
	CoverUrl       string `form:"cover_url"`
	StartDate      int    `form:"start_date" binding:"required"`
	EndDate        int    `form:"end_date" binding:"required"`
	TypeId         int    `form:"type_id" binding:"required"`
	ScheduleDetail string `form:"schedule_detail"`
	HotelDetail    string `form:"hotel_detail"`
}

// GetItineraryDetailRequest 查看行程详细信息
type GetItineraryDetailRequest struct {
	ItineraryId int `form:"itinerary_id" binding:"required"`
}

func (svc Service) GetAllItinerary(userId int, param *GetAllItineraryRequest) ([]*model.ItineraryPart, error) {
	return svc.dao.FindAllItinerary(userId, app.GetPageOffset(param.Page, param.PageSize), param.PageSize)
}

func (svc Service) PublishItinerary(userId int, param *PublishItineraryRequest) error {
	// 检查日程安排部分是否符合规范
	_, err := getScheduleList(param.ScheduleDetail)
	if err != nil {
		return err
	}

	// 检查酒店信息是否符合规范
	_, err = getHotelInformation(param.HotelDetail)
	if err != nil {
		return err
	}

	return svc.dao.CreateItinerary(param.Title, param.Slogan, param.CoverUrl,
		param.ScheduleDetail, param.HotelDetail, param.StartDate, param.EndDate,
		param.TypeId, userId)
}

func (svc Service) GetItineraryDetail(param *GetItineraryDetailRequest) (*model.ItineraryDetail, error) {
	detail, err := svc.dao.GetItineraryDetail(param.ItineraryId)
	if err != nil {
		return nil, err
	}

	scheduleList, err := getScheduleList(detail.ScheduleDetail)
	if err != nil {
		return nil, err
	}

	hotelInformation, err := getHotelInformation(detail.HotelDetail)
	if err != nil {
		return nil, err
	}

	detail.ScheduleList = scheduleList
	detail.HotelInformation = hotelInformation

	return detail, nil
}

// 声明错误：解析失败
var parseErr = errors.New("parsing failed")

func getScheduleList(scheduleDetail string) ([]*model.TourismSchedule, error) {
	// 字符串格式 20220110&1,2,4&带上雨伞&某某山*42.5*25.4*地址*描述,某某河*42.5*25.4*地址*描述
	// 解释：日期&旅游项目&旅游攻略&地点*经度*纬度*地址*描述%下一个行程

	if scheduleDetail == "" {
		return nil, nil
	}

	var scheduleList []*model.TourismSchedule

	// 解析字符串，拆分成单个的行程
	scheduleStrList := strings.Split(scheduleDetail, "%")

	// 对每个行程字符串再进行解析
	for _, scheduleString := range scheduleStrList {

		contents := strings.Split(scheduleString, "&")

		if len(contents) != 4 {
			return nil, parseErr
		}

		// 日期解析
		date, err := strconv.Atoi(contents[0])
		if err != nil {
			return nil, err
		}

		// 旅游项目列表解析
		var projects []int
		projectStrList := strings.Split(contents[1], ",")
		for _, projectStr := range projectStrList {
			projectId, err := strconv.Atoi(projectStr)
			if err != nil {
				return nil, err
			}
			projects = append(projects, projectId)
		}

		// 旅游攻略解析
		introduction := contents[2]

		// 旅游路线解析
		var routes []*model.Location
		routeStrList := strings.Split(contents[3], ",")
		for _, routeStr := range routeStrList {
			route, err := getLocation(routeStr)
			if err != nil {
				return nil, err
			}

			routes = append(routes, route)
		}

		schedule := &model.TourismSchedule{
			Date:         date,
			Projects:     projects,
			Introduction: introduction,
			Routes:       routes,
		}

		scheduleList = append(scheduleList, schedule)
	}

	return scheduleList, nil
}

func getHotelInformation(hotelDetail string) (*model.HotelInformation, error) {
	// 地点*经度*纬度*地址*描述&价位

	if hotelDetail == "" {
		return nil, nil
	}

	contents := strings.Split(hotelDetail, "&")
	if len(contents) != 2 {
		return nil, parseErr
	}

	// 解析位置
	location, err := getLocation(contents[0])
	if err != nil {
		return nil, err
	}

	// 解析价格
	price, err := strconv.Atoi(contents[1])
	if err != nil {
		return nil, err
	}

	hotel := &model.HotelInformation{
		Location: location,
		Price:    price,
	}

	return hotel, nil
}

func getLocation(locationStr string) (*model.Location, error) {
	// 地点*经度*纬度*地址*描述

	content := strings.Split(locationStr, "*")
	if len(content) != 5 {
		return nil, parseErr
	}

	// 检测名称非空
	if content[0] == "" {
		return nil, parseErr
	}

	longitude, err := strconv.ParseFloat(content[1], 64)
	if err != nil {
		return nil, err
	}

	latitude, err := strconv.ParseFloat(content[2], 64)
	if err != nil {
		return nil, err
	}

	location := &model.Location{
		Name:        content[0],
		Longitude:   longitude,
		Latitude:    latitude,
		Address:     content[3],
		Description: content[4],
	}

	return location, nil
}
